import { LabelWithTips } from "@renderer/components/business/label-with-tips";
import { Slider } from "@renderer/components/ui/base/slider";
import { getStepDecimalPlaces } from "@renderer/utils/math";
import { isUndefined } from "es-toolkit";
import { useTranslation } from "react-i18next";

interface ParametersSliderProps {
  label: string;
  tips?: string;

  min: number;
  max: number;
  value: number | null;
  step: number;
  onChange: (value: number | null) => void;
}

export function ParametersSlider({
  label,
  tips,
  min,
  max,
  value,
  step,
  onChange,
}: ParametersSliderProps) {
  const { t } = useTranslation("translation", {
    keyPrefix: "chat.tool-bar.parameters",
  });

  /**
   * Step-count mapping (piecewise UI percent scale)
   *
   * UI slider uses a 0–100 percent scale with a reserved OFF segment.
   * - 0% represents Off
   * - OFF_PERCENT% represents Min
   * - The remaining (100 - OFF_PERCENT)% is evenly divided into `totalSteps`
   *   to represent values from Min to Max.
   *
   * This guarantees a consistent visual distance from Off → Min, regardless of
   * the numeric range or the step size.
   */
  const isOff = value === null;
  const effectiveStep = step > 0 ? step : 1;
  const totalSteps = Math.max(0, Math.round((max - min) / effectiveStep));
  const OFF_PERCENT = 10; // fixed visual distance (%) between Off (0%) and Min
  const STEP_PERCENT = totalSteps > 0 ? (100 - OFF_PERCENT) / totalSteps : 0;
  const decimalPlaces = getStepDecimalPlaces(effectiveStep);

  /**
   * Converts a business value to the UI slider percent in [0, 100].
   *
   * @param val - The business value in [min, max] or null to represent Off.
   * @returns The slider percent: 0 for Off, otherwise OFF_PERCENT + stepIndex*STEP_PERCENT.
   */
  const mapValueToSliderPercent = (val: number | null) => {
    if (val === null) return 0;
    if (totalSteps <= 0) return OFF_PERCENT;
    const stepIndex = Math.round((val - min) / effectiveStep);
    const clampedIndex = Math.max(0, Math.min(totalSteps, stepIndex));
    return OFF_PERCENT + clampedIndex * STEP_PERCENT;
  };

  /**
   * Converts a UI slider percent to the business value.
   *
   * @param percent - Slider position in [0, 100]. 0 → Off; >= OFF_PERCENT → Min..Max.
   * @returns The mapped business value in [min, max], or null if Off.
   */
  const mapSliderPercentToValue = (percent: number): number | null => {
    // Midpoint between Off(0) and Min(OFF_PERCENT) decides the snap
    const offThreshold = OFF_PERCENT / 2;
    if (percent <= offThreshold) return null;
    if (totalSteps <= 0) return min;

    const rawIndex = (percent - OFF_PERCENT) / STEP_PERCENT;
    const clampedIndex = Math.max(
      0,
      Math.min(totalSteps, Math.round(rawIndex)),
    );

    // Compute value from index; snap to max at rightmost index
    if (clampedIndex === totalSteps) return Number(max.toFixed(decimalPlaces));
    const v = min + clampedIndex * effectiveStep;
    return Number(Math.max(min, Math.min(max, v)).toFixed(decimalPlaces));
  };

  /**
   * Snap the UI percent to the nearest allowed anchor:
   * - 0 (Off)
   * - OFF_PERCENT + k*STEP_PERCENT for k in [0..totalSteps]
   */
  const snapPercent = (percent: number): number => {
    if (Math.abs(percent - 0) <= Math.abs(percent - OFF_PERCENT)) return 0;

    if (STEP_PERCENT <= 0 || totalSteps <= 0) return OFF_PERCENT;
    const k = Math.round((percent - OFF_PERCENT) / STEP_PERCENT);
    const clamped = Math.max(0, Math.min(totalSteps, k));
    return OFF_PERCENT + clamped * STEP_PERCENT;
  };

  /**
   * Dynamic label widths (Off + value range)
   */
  const offSegmentWidth = `${OFF_PERCENT}%`;
  const valueRangeWidth = `${100 - OFF_PERCENT}%`;

  return (
    <div className="flex flex-col gap-y-2">
      <Slider
        output="none"
        label={
          <div className="flex w-full items-center">
            {isUndefined(tips) ? (
              <span className="text-label-fg">{label}</span>
            ) : (
              <LabelWithTips
                label={label}
                tips={tips}
                tooltipPlacement="right"
              />
            )}
            <span className="ml-auto text-fg text-sm tabular-nums">
              {isOff ? t("off") : (value as number).toFixed(decimalPlaces)}
            </span>
          </div>
        }
        value={mapValueToSliderPercent(value)}
        // Use a fine-grained step and snap in onChange to the nearest anchor percent
        minValue={0}
        maxValue={100}
        step={0.1}
        onChange={(p) => {
          const percent = typeof p === "number" ? p : p[0];
          const snapped = snapPercent(percent);
          const mapped = mapSliderPercentToValue(snapped);
          onChange(mapped);
        }}
      />

      <div className="flex flex-1 flex-row text-muted-fg text-xs">
        <span style={{ width: offSegmentWidth }}>{t("off")}</span>
        <span
          className="flex flex-row justify-between"
          style={{ width: valueRangeWidth }}
        >
          <span>{min.toFixed(decimalPlaces)}</span>
          <span>{max.toFixed(decimalPlaces)}</span>
        </span>
      </div>
    </div>
  );
}
